﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using DDD;
using System.Drawing;

namespace DevApp {
    public class Program6 : GameWindow {

        World wld;
        Graphics3D g3d;
        Image2D colorImage;
        Image2D depthImage;

        public Program6 ()
            : base (640, 480,
              new GraphicsMode (), "DDD: Offline rendering", 0,
              DisplayDevice.Default, 3, 0,
              GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug) {
        }

        private Appearance CreateAppearance () {
            var vert = new VertexShader ("Shaders/simple.vert");
            var frag = new FragmentShader ("Shaders/simple.frag");
            var sp = new ShaderProgram (vert, frag);

            var unifs1 = new UniformArray ();
            unifs1.Add ("ModelViewMatrix", UniformArray.CurrentNode, () => ((Node)null).LocalToCamera);
            unifs1.Add ("ProjectionMatrix", UniformArray.CurrentActiveCamera, () => ((Camera)null).ProjectionMatrix);

            var unifs2 = new UniformArray ();
            unifs2.Add ("Diffuse", UniformArray.CurrentMaterial, () => ((PhongMaterial)null).Diffuse);

            var mat = new PhongMaterial ();
            mat.SetDiffuse (1, 1, 1, 1);

            var app = new Appearance ();
            app.SetShaderProgram (sp);
            app.AddUniformArray (unifs1);
            app.AddUniformArray (unifs2);
            app.SetMaterial (mat);

            return app;
        }



        protected override void OnLoad (System.EventArgs e) {

            var msh1 = MeshBuilder.CreateSquare (5, 1, 1, "v_Position", null, "v_TexCoord");
            msh1.SetAppearance (CreateAppearance ());

            var nodMesh1 = new Node ();
            nodMesh1.Attach (msh1);

            var msh2 = MeshBuilder.CreateSquare (3, 1, 1, "v_Position", null, null);
            msh2.SetAppearance (CreateAppearance ());
            ((PhongMaterial)msh2.Appearance.Material).SetDiffuse (1, 0, 0.2f, 1);

            var nodMesh2 = new Node ();
            nodMesh2.Attach (msh2);
            nodMesh2.Translate (3, 0, 0.1f);  // 右手前

            var cam = new Camera ();
            cam.SetPerspective (45, Width / (float)Height, 5.0f, 30f);

            var nodCam = new Node ();
            nodCam.Attach (cam);
            nodCam.SetTranslation (0, 0, 10);

            wld = new World ();
            wld.AddChild (nodMesh1);
            wld.AddChild (nodMesh2);
            wld.AddChild (nodCam);
            wld.SetActiveCamera (nodCam);

            var fbuf = new FrameBuffer (1, 1, 0);
            colorImage = new Image2D<float> (DDD.PixelFormat.RGBA8, 256, 256);
            depthImage = new Image2D<float> (DDD.PixelFormat.Depth, 256, 256);
            fbuf.SetColorBuffer (0, colorImage);
            fbuf.SetDepthBuffer (depthImage);


            g3d = Graphics3D.GetInstance ();


            // 1st pass : Render To Texture
            g3d.RenderPass += delegate {
                g3d.SetWorld (wld);
                //g3d.SetFrameBuffer (fbuf);                 // オフライン用フレームバッファーに変更
                g3d.SetClearColor (0.2f, 0.2f, 1.0f, 1);   // 赤
                g3d.SetClearDepth (1);
                g3d.SetColorClearEnabled (true);
                g3d.SetDepthClearEnabled (true);
                g3d.SetViewort (0, 0, 256, 256);

                //msh1.Appearance.AddSampler (0, null);
            };


            // 未実装
            VSync = VSyncMode.On;
        }

        protected override void OnUnload (EventArgs e) {
            wld = null;
            GC.Collect ();
            g3d.Release ();
        }

        protected override void OnUpdateFrame (FrameEventArgs e) {
            if (Keyboard[OpenTK.Input.Key.Escape])
                Exit ();
            if (Keyboard[OpenTK.Input.Key.Space]) {
                colorImage.Capture ();
                colorImage.Save ("Capture-Color.png");
                //depthImage.Capture ();
                //depthImage.Save ("Capture-Depth.png");
            }
            if (caputured) {
                Exit ();
            }
         }

        bool caputured = false;

        protected override void OnRenderFrame (FrameEventArgs e) {
            
            g3d.Render ();
            SwapBuffers ();

            //colorImage.Capture ();
            //colorImage.Save ("Capture-Color.png");
            //depthImage.Capture ();
            //depthImage.Save ("Capture-Depth.png");
            //caputured = true;
        }

        /*
        [STAThread]
        public static void Main () {
            using (var example = new Program6 ()) {
                example.Run (30);
            }
        }
        */

    }
}
